/*
 * This file is Copyright 2002-2006 Loyola University Chicago,
 * Department of Computer Science and the Emerging Technologies Laboratory.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License via
 *    http://www.apache.org/licenses/LICENSE-2.0.
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.citep.web.admin.transactions.client;


import com.citep.web.admin.accounts.client.AccountService;
import com.citep.web.admin.accounts.client.AccountServiceAsync;
import com.citep.web.gwt.cache.AccountTreeCache;
import com.citep.web.gwt.dto.AccountDTO;
import com.citep.web.gwt.dto.ImportedEntryDTO;
import com.citep.web.gwt.dto.StatementDTO;
import com.citep.web.gwt.module.BaseApplication;
import com.citep.web.gwt.widgets.DynaTableDataProvider;
import com.citep.web.gwt.widgets.DynaTableDataProvider.RowDataAcceptor;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.rpc.ServiceDefTarget;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Date;

public class TransactionImportApplication extends BaseApplication implements ImportedStatementProvider {
	private TransactionImportPresentation presentation;
	private AccountServiceAsync accountsService;
	
	private HashMap statements = new HashMap();
	
	protected AccountTreeCache cache = AccountTreeCache.getCache();	
	
	public TransactionImportApplication() {
		accountsService = (AccountServiceAsync)GWT.create(AccountService.class);
		((ServiceDefTarget)accountsService).setServiceEntryPoint(GWT.getModuleBaseURL() + "/accounts");		
	}
	
	public void setPresentation(TransactionImportPresentation presentation) {
		this.presentation = presentation;
	}
	
	public void onUploadComplete(String msg) {
		String [] tokens = msg.split("__");
		
		if(tokens.length < 3) {
			//presentation.displayError("", "Invalid token return: " + msg);
			return;
		}

		for(int i = 0; i < tokens.length; i++)
			System.out.println(i + ": " + tokens[i]);
		
		if("OK".equals(tokens[1])) {
			int numStatements = Integer.parseInt(tokens[2]);
			int numEntries = Integer.parseInt(tokens[3]);
			presentation.displayStatus("Found " + numStatements + " statements with " + numEntries + " entries. Please wait...",0);
			presentation.showEntryReview();
			
			//retrieve transactions for each statement
			for(int i = 0; i < numStatements; i++) {
				getTransactions(i);
			}
			
		} else if("ERR".equals(tokens[1])) {
			presentation.displayError("", tokens[2]);
			presentation.enableCurrentStep();
		}
		
	}
	
	public void getTransactions(final int statementNumber) {
		accountsService.getImportedTransactions(statementNumber, new AsyncCallback() {

			public void onFailure(Throwable caught) {
				processException(presentation, caught);
			}

			public void onSuccess(Object result) {
				StatementDTO statement = (StatementDTO)result;
				ArrayList transactions = statement.getTransactions();
				statements.put(new Integer(statementNumber), transactions);
				presentation.addStatement(statementNumber,statement.getAccountName());
				presentation.showEntryReview();
				presentation.displayStatus("Statements loaded", 3);
			}
			
		});
	}

	protected String formatDate(Date d) {
		return "" + (d.getMonth()+1) + "/" + d.getDate() + "/" + (d.getYear() + 1900);
	}
	
	protected void pushResults(ArrayList entryList, int startRow, RowDataAcceptor acceptor) {
		int listSize = entryList.size();
		
		String [][] rows = new String[listSize][];
		
		for(int i = 0; i < listSize; i++) {
			ImportedEntryDTO entry = (ImportedEntryDTO)entryList.get(i);
			rows[i] = new String[6];
			rows[i][0] = formatDate(entry.getEntryDate());
			rows[i][1] = entry.getMemo();
			
			int sourceAccountId = entry.getSourceAccountId();
			if(sourceAccountId != 0) {
				System.out.println("account id:" + sourceAccountId);
				AccountDTO source = cache.getAccount(sourceAccountId);
				rows[i][2] = (source != null)?source.getName():"null";
			} else {
				rows[i][2] = "unbalanced";
			}
			
			//rows[i][2] = currentAccount.getName();
			
			if(entry.getType().equals("DEBIT")) {
				rows[i][3] = entry.getAmount();
			} else if(entry.getType().equals("CREDIT")) {
				rows[i][4] = entry.getAmount();
			}

		}
		
		acceptor.accept(startRow, rows);
	}
	
	
	public void updateRowData(int statementNumber, int startRow, int maxRows, RowDataAcceptor acceptor) {
		if(!statements.containsKey(new Integer(statementNumber))) {
			presentation.displayError("", "Could not find statement #" + statementNumber);
			return;
		}
		
		System.out.println("Update row data: " + startRow + " " + maxRows);
		
		ArrayList transactions = (ArrayList)statements.get(new Integer(statementNumber));
		
		if(startRow > transactions.size())
			return;
		
		ArrayList results = new ArrayList();
		int limit = startRow + maxRows;
		for(int i = startRow; i < transactions.size() && i < limit; i++)
			results.add(transactions.get(i));
		
		pushResults(results, startRow, acceptor);
	}
	
	public void checkForPendingStatements() {
		//check that the user has no pending
		//statements to be imported in the browser's
		//session.
		accountsService.getPendingStatementCount(new AsyncCallback() {
			public void onFailure(Throwable caught) {
				processException(presentation, caught);
			}

			public void onSuccess(Object result) {
				Integer statementCount = (Integer)result;
				if(statementCount.intValue() < 1) {
					//there are no pending statements,
					//show the user the file upload dialog
					presentation.showFileImport();
				} else {
					//there are pending statements,
					//the user must review these first
					presentation.clearStatements();
					for(int i = 0; i < statementCount.intValue(); i++) {
						getTransactions(i);
					}
				}
			} 
		});
	}
	
	public void onCellChanged(final int statementNumber, final int idx, final AccountDTO account) {
		presentation.displayStatus("Updating...", 0);
		accountsService.setImportedTransactionAccount(statementNumber, idx, account, new AsyncCallback() {
			public void onFailure(Throwable caught) {
				processException(presentation, caught);
				presentation.displayStatus("", 0);
			}

			public void onSuccess(Object result) {
				ArrayList transactions = (ArrayList)statements.get(new Integer(statementNumber));
				if(idx < transactions.size()) {
					ImportedEntryDTO entry = (ImportedEntryDTO)transactions.get(idx);
					entry.setSourceAccountId(account.getId());
				}
				presentation.displayStatus("", 0);
			}
		});
	}
	
	public void commitStatement(final int statementNumber, final AccountDTO destination) {
		presentation.displayStatus("Commiting statement...", 0);
		accountsService.commitStatementImport(statementNumber, destination, new AsyncCallback () {
			public void onFailure(Throwable caught) {
				processException(presentation, caught);
				presentation.getStatusLabel().hide();
			}

			public void onSuccess(Object result) {
				presentation.displayStatus("done!",3);
				checkForPendingStatements();
			}
		});
	}
}
